﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows;
using Microsoft.Win32;
using System.Windows.Controls;
using System.Threading.Tasks;
using System.Globalization;
using System.Threading;

namespace PracaInz_v0
{
    class TreeD
    {
        public delegate bool delegatVerificationNode(nodesLR nodeLR, double chMVN, int chMNV, int chMNVP);
        public delegate nodesLR delegat1(double[][] AJ, int mNNCH); 

        //public static double[][] AJ;
        String date; //nazwa dla katalogu

        public int GNN=0, L = 1, N = 1, P = 0;
        //GNN-Global Node Number | L-Level | N-Node | P-Parent |
        //mL - Max Level    

        //wczytywanie pliku
        static char[] charSeparators = new char[] { ' ', '\t', ';' };   

        //regula stopu
        public double mVN; //minimalna wariancja wezla
        public int mNV; //minimalna ilosc wektorow potomka L lub R
        public int mL ; //max poziom
        public int mNVP;//minimalna  licznosc potomka rodzica
        public Queue<int> PNS= new Queue<int>();
        public string FileNameTreeQ;
        public string fileNameT;

        // dowyswietlania w datagrid
        public DataTable TreeDT;         //do widoku
        public DataTable SymulationDT;
        public DataTable NodeVectSource; //do widoku
        public string Quality;

        public double[][] AJ;
        public double[][] AJTree;
        public double[][] AJTrain;
        public double[][] AJT;

        public StreamReader rf;

        static string rootDirName;
        public string rootDirNameC;

        
        public TreeD()
        {
            NodeVectSource = new DataTable();
            NodeVectSource.Columns.Add("NodeID", typeof(int));
            NodeVectSource.Columns.Add("Source", typeof(string));
        }

        public static void CreateRootDir(string n)
        {
            rootDirName = "Dane-" + n + "-" + DateTime.Now.ToString("yyyyMMdd-HHmmss");
            Directory.CreateDirectory(rootDirName);
        }

        public void Tree(TreeViewSettings TVS, String name, delegat1 metodaD, delegatVerificationNode verificationNodeT)
        {            
            // dane poczatkowe
            int nL = 2, nR = 3, nF = 1;// numery plików poczatkowych 

            date = DateTime.Now.ToString("yyyyMMdd-HHmmss");
            String nfile = "00";// numeru 
            rootDirNameC = "Dane" + name + date;
            String fileName = "Dane" + name + date + "\\Set" + nfile + nF + ".txt";
            String fileNameL = "Dane" + name + date + "\\Set" + nfile + nL + ".txt";
            String fileNameR = "Dane" + name + date + "\\Set" + nfile + nR + ".txt";
            fileNameT = "Dane" + name + date + "\\Tree.txt";
            FileNameTreeQ = "Dane" + name + date + "\\TreeQ.txt";
            
            NodeVectSource.Rows.Add(new object[] { nF, Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\" + fileName });

            StreamWriter wfR;
            StreamWriter wfL;
            int nN = 0, nN2 = 1, nP = 1; // zmienne potrzebne do zmiany poziomu rodzica wezla
            int numFile = 1;// do sprawdzania czy sa pliki jeszcze do wczytania

            //tworzenie katalogu            
            Directory.CreateDirectory(@"Dane"+name+ date);//tworzenie katalogu DANE+DATA+CZAS
           
            FileStream fsT = new FileStream(fileNameT, FileMode.Append, FileAccess.Write);//Tworzenie plików tree do zapisywania wezlow sredniej wariancji itd...
            StreamWriter wfT = new StreamWriter(fsT);
            DataTable dt = new DataTable();
            dt.Columns.Add(new DataColumn("GNNumber", typeof(string)));
            dt.Columns.Add(new DataColumn("Level", typeof(string)));
            dt.Columns.Add(new DataColumn("Node", typeof(string)));
            dt.Columns.Add(new DataColumn("Parent", typeof(string)));
            dt.Columns.Add(new DataColumn("ChildL", typeof(string)));
            dt.Columns.Add(new DataColumn("ChildR", typeof(string)));
            dt.Columns.Add(new DataColumn("Mean", typeof(string)));
            dt.Columns.Add(new DataColumn("Variance", typeof(string)));
            dt.Columns.Add(new DataColumn("NumVect", typeof(string)));
            dt.Columns.Add(new DataColumn("SANumber", typeof(string)));
            dt.Columns.Add(new DataColumn("SAValue", typeof(string)));
            
            wfT.WriteLine("GNNumber Level    Node    Parent  ChildL  ChildR  Mean        Variance    NumVect SANumber    SAValue");             

            {//tworzenie pierwszego pliku do wczytania

                saveFile(fileName);//zapisujemy pierwszy plik do wczytania
            }

            int nRL = AJ[0].Length;//max ilosc powtorzen petli


            for (int w = 1; w < nRL; w++)//Wczyttywanie wezla z nr----------------------------------------------------------
            {
                DataRow dr = dt.NewRow();
                if (w > numFile) { break; }//przerywanie petli gdy juz nie ma wiecej plikow do wczytania

                if (nP == 2) { P++; nP = 0; }//zmiana rodzica

                GNN++; //wezel globalny

                fileName = "Dane" + name + date + "\\Set" + nfile + w + ".txt";//wczytywanie wezla
                {
                    readFile(fileName);//wczytywanie pliku do obliczen
                }              
                
                while (PNS.Count > 0)//sprawdzanie czy wezel sie dzielil na CHL i CHR 
                {
                    if (P==(int)PNS.Peek() )
                    {
                        PNS.Dequeue();
                        P++;
                    }
                    else
                    {
                        break;
                    }
                }

                nodesLR node = metodaD(AJ, mNV);//metoda szuka najlepszego punktu podzialu i zwraca wezel dla Tree
                node.L = L;
                node.GNN = GNN;
                node.N = N;
                node.P = P;
                node.CHL = nL;
                node.CHR = nR;
               
                    if (verificationNodeT(node, mVN, mNV, mNVP)) //if sprawdzajcy czy var q CHL i CHR jest wieksza od minimalnej i sprawdza tez ilosc wektorow
                    {
                       
                        nN += 2;
                        numFile += 2; //zliczanie plikow

                        //po sprawdzeniu tworzymy plik z wezlami
                        fileNameL = "Dane" + name + date + "\\Set" + nfile + nL + ".txt";
                        fileNameR = "Dane" + name + date + "\\Set" + nfile + nR + ".txt";

                        NodeVectSource.Rows.Add(new object[] { nL, Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\" + fileNameL });
                        NodeVectSource.Rows.Add(new object[] { nR, Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\" + fileNameR });

                        FileStream fsL = new FileStream(fileNameL, FileMode.Append, FileAccess.Write);//Tworzenie plików do zapisywania zbiorow L
                        FileStream fsR = new FileStream(fileNameR, FileMode.Append, FileAccess.Write);//Tworzenie plików do zapisywania zbiorow P

                        wfR = new StreamWriter(fsR);
                        wfL = new StreamWriter(fsL);

                        for (int i = 0; i < AJ[0].Length; i++)//zapisywanie wektorow do plikow L i R 
                        {
                           // rVerification.AppendText("Tree" + "  SV =" + AJ[node.SAN - 1][i]+"SAV  "+node.SAV+ "\n");

                            if (node.isV1A)
                            {
                                if (node.ML < node.MR)// jesli varL jest wieksze, to zamiana zbiorow z L na R
                                {

                                    if (AJ[node.SAN - 1][i] < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                    {
                                        for (int j = 0; j < AJ.Length; j++)
                                        {
                                            wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                        }
                                        wfL.WriteLine();
                                    }
                                    else
                                    {
                                        for (int j = 0; j < AJ.Length; j++)
                                        {
                                            wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                        }
                                        wfR.WriteLine();
                                    }
                                }
                                else
                                {
                                    if (AJ[node.SAN - 1][i] < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                    {
                                        for (int j = 0; j < AJ.Length; j++)
                                        {
                                            wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                        }
                                        wfR.WriteLine();
                                    }
                                    else
                                    {
                                        for (int j = 0; j < AJ.Length; j++)
                                        {
                                            wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                        }
                                        wfL.WriteLine();
                                    }
                                }
                            }
                            else//---------------------------------------------V2A------------------------------------
                            {

                                double vAS = 0; // wartosc dwoch atrybutow podzoalu
                                   
                                    if (node.mA < 7)// sprawdzanie ktory atrybut ma byc mnozony
                                    {
                                        vAS = AJ[node.nC1][i] + AJ[node.nC2][i] * node.lS;
                                    }
                                    else
                                    {
                                        vAS = AJ[node.nC1][i] * node.lS + AJ[node.nC2][i];
                                    }

                                if (node.ML < node.MR)// jesli varL jest wieksze, to zamiana zbiorow z L na R
                                {                            
   
                                    if (vAS < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                    {
                                        for (int j = 0; j < AJ.Length; j++)
                                        {
                                            wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                        }
                                        wfL.WriteLine();
                                    }
                                    else
                                    {
                                        for (int j = 0; j < AJ.Length; j++)
                                        {
                                            wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                        }
                                        wfR.WriteLine();
                                    }
                                }
                                else
                                {                                 

                                    if (vAS< node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                    {
                                        for (int j = 0; j < AJ.Length; j++)
                                        {
                                            wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                        }
                                        wfR.WriteLine();
                                    }
                                    else
                                    {
                                        for (int j = 0; j < AJ.Length; j++)
                                        {
                                            wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                        }
                                        wfL.WriteLine();
                                    }
                                }
                            }
                        }

                        if(node.L != mL)
                            wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       " + node.CHL + "       " + node.CHR + "       " + Math.Round(node.M, 5) + "      " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree                        
                        else
                            wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       0       0       " + Math.Round(node.M, 5) + "      " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree

                        nL += 2;// zwiekszamy nazwe pliku o 2
                        nR += 2;// zwiekszamy nazwe pliku o 2

                        wfL.Close();
                        wfR.Close();

                    }//koniec if sprawdzajacy CHL i CHR czy sie dzieli
                    else
                    {
                        
                        PNS.Enqueue(node.GNN);//jesli sie rodzic nie dzieli to musimy zapamietac
                        if (node.M == 0)
                        {
                            node.M = average(AJ[AJ.Length - 1]); node.V = variance(AJ[AJ.Length - 1], average(AJ[AJ.Length - 1]));
                            node.NV = AJ[0].Length;
                        }
                        if (node.NV < mNV || node.V < mVN) { node.SAN = 0; node.SAV = 0; node.NV = AJ[0].Length; }

                        node.CHR = 0;
                        node.CHL = 0;
                        //rVerification.AppendText(Convert.ToString(node.GNN + "                   " + node.L + "             " + node.N + "              " + node.P + "           " + node.CHL + "           " + node.CHR + "       " + Math.Round(node.M, 5) + "        " + Math.Round(node.V, 5) + "       " + node.NV + "       " + node.SAN + "         " + Math.Round(node.SAV, 5) + "\n"));

                        wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       0       0       " + Math.Round(node.M, 5) + "      " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree
                        
                    }

                    dr[0] = node.GNN.ToString();
                    dr[1] = node.L.ToString();
                    dr[2] = node.N.ToString();
                    dr[3] = node.P.ToString();
                    dr[4] = node.CHL.ToString();
                    dr[5] = node.CHR.ToString();
                    dr[6] = Math.Round(node.M, 5).ToString();
                    dr[7] = Math.Round(node.V, 5).ToString();
                    dr[8] = node.NV.ToString();
                    dr[9] = node.SAN.ToString();
                    dr[10] = Math.Round(node.SAV, 5).ToString();

                    dt.Rows.Add(dr);

                if (N == nN2) { L++; nN2 = nN; nN = 0; N = 0; }//zwiekszanie poziomu gdy przejdziemy przez wszystkie wezly na danym poziomie
                N++;
                nP++;// do zmiany rodzica 

                if (L > mL) {  break; } //po osiegnieciu poziomu konczymy 
                
            } //petla dla wezla w            
            wfT.Close(); // zamykanie plik    
            TVS.DataViewGridTree = dt.DefaultView;

            GNN = 0; L = 1; N = 1; P = 0;

            //zapisywanie NodeVectSource
            saveNodeVectSource();

            AJ = null;
            GC.Collect();
        }//TreeD  

        public void Tree(String name, delegat1 metodaD, delegatVerificationNode verificationNodeT, int IDT)
        {
            // dane poczatkowe
            int nL = 2, nR = 3, nF = 1;// numery plików poczatkowych 

            String nfile = "00";// numeru 
            String fileName = rootDirName + "\\IDT" + IDT + "-" + name + "\\Set" + nfile + nF + ".txt";
            String fileNameL = rootDirName + "\\IDT" + IDT + "-" + name + "\\Set" + nfile + nL + ".txt";
            String fileNameR = rootDirName + "\\IDT" + IDT + "-" + name + "\\Set" + nfile + nR + ".txt";
            fileNameT = rootDirName + "\\IDT" + IDT + "-" + name + "\\Tree.txt";

            NodeVectSource.Rows.Add(new object[] { nF, Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\" + fileName });

            StreamWriter wfR;
            StreamWriter wfL;
            int nN = 0, nN2 = 1, nP = 1; // zmienne potrzebne do zmiany poziomu rodzica wezla
            int numFile = 1;// do sprawdzania czy sa pliki jeszcze do wczytania

            //tworzenie katalogu            
            Directory.CreateDirectory(rootDirName + "\\IDT" + IDT + "-" + name + date);//tworzenie katalogu 

            FileStream fsT = new FileStream(fileNameT, FileMode.Append, FileAccess.Write);//Tworzenie plików tree do zapisywania wezlow sredniej wariancji itd...
            StreamWriter wfT = new StreamWriter(fsT);
            TreeDT = new DataTable();
            TreeDT.Columns.Add(new DataColumn("GNNumber", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("Level", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("Node", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("Parent", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("ChildL", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("ChildR", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("Mean", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("Variance", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("NumVect", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("SANumber", typeof(string)));
            TreeDT.Columns.Add(new DataColumn("SAValue", typeof(string)));

            wfT.WriteLine("GNNumber Level    Node    Parent  ChildL  ChildR  Mean        Variance    NumVect SANumber    SAValue");
            {//tworzenie pierwszego pliku do wczytania

                saveFile(fileName);//zapisujemy pierwszy plik do wczytania
            }

            int nRL = AJ[0].Length;//max ilosc powtorzen petli


            for (int w = 1; w < nRL; w++)//Wczyttywanie wezla z nr----------------------------------------------------------
            {
                DataRow dr = TreeDT.NewRow();
                if (w > numFile) { break; }//przerywanie petli gdy juz nie ma wiecej plikow do wczytania

                if (nP == 2) { P++; nP = 0; }//zmiana rodzica

                GNN++; //wezel globalny

                fileName = rootDirName + "\\IDT" + IDT + "-" + name + "\\Set" + nfile + w + ".txt";//wczytywanie wezla
                {
                    readFile(fileName);//wczytywanie pliku do obliczen
                }

                while (PNS.Count > 0)//sprawdzanie czy wezel sie dzielil na CHL i CHR 
                {
                    if (P == (int)PNS.Peek())
                    {
                        PNS.Dequeue();
                        P++;
                    }
                    else
                    {
                        break;
                    }
                }

                nodesLR node = metodaD(AJ, mNV);//metoda szuka najlepszego punktu podzialu i zwraca wezel dla Tree
                node.L = L;
                node.GNN = GNN;
                node.N = N;
                node.P = P;
                node.CHL = nL;
                node.CHR = nR;

                if (verificationNodeT(node, mVN, mNV, mNVP)) //if sprawdzajcy czy var q CHL i CHR jest wieksza od minimalnej i sprawdza tez ilosc wektorow
                {
                    nN += 2;
                    numFile += 2; //zliczanie plikow

                    //po sprawdzeniu tworzymy plik z wezlami
                    fileNameL = rootDirName + "\\IDT" + IDT + "-" + name + "\\Set" + nfile + nL + ".txt";
                    fileNameR = rootDirName + "\\IDT" + IDT + "-" + name + "\\Set" + nfile + nR + ".txt";

                    NodeVectSource.Rows.Add(new object[] { nL, Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\" + fileNameL });
                    NodeVectSource.Rows.Add(new object[] { nR, Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + "\\" + fileNameR });

                    FileStream fsL = new FileStream(fileNameL, FileMode.Append, FileAccess.Write);//Tworzenie plików do zapisywania zbiorow L
                    FileStream fsR = new FileStream(fileNameR, FileMode.Append, FileAccess.Write);//Tworzenie plików do zapisywania zbiorow P

                    wfR = new StreamWriter(fsR);
                    wfL = new StreamWriter(fsL);

                    for (int i = 0; i < AJ[0].Length; i++)//zapisywanie wektorow do plikow L i R 
                    {
                        // rVerification.AppendText("Tree" + "  SV =" + AJ[node.SAN - 1][i]+"SAV  "+node.SAV+ "\n");

                        if (node.isV1A)
                        {
                            if (node.ML < node.MR)// jesli varL jest wieksze, to zamiana zbiorow z L na R
                            {

                                if (AJ[node.SAN - 1][i] < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfL.WriteLine();
                                }
                                else
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfR.WriteLine();
                                }
                            }
                            else
                            {
                                if (AJ[node.SAN - 1][i] < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfR.WriteLine();
                                }
                                else
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfL.WriteLine();
                                }
                            }
                        }
                        else//---------------------------------------------V2A------------------------------------
                        {

                            double vAS = 0; // wartosc dwoch atrybutow podzoalu

                            if (node.mA < 7)// sprawdzanie ktory atrybut ma byc mnozony
                            {
                                vAS = AJ[node.nC1][i] + AJ[node.nC2][i] * node.lS;
                            }
                            else
                            {
                                vAS = AJ[node.nC1][i] * node.lS + AJ[node.nC2][i];
                            }

                            if (node.ML < node.MR)// jesli varL jest wieksze, to zamiana zbiorow z L na R
                            {

                                if (vAS < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfL.WriteLine();
                                }
                                else
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfR.WriteLine();
                                }
                            }
                            else
                            {

                                if (vAS < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfR.WriteLine();
                                }
                                else
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfL.WriteLine();
                                }
                            }
                        }
                    }

                    if (node.L != mL)
                        wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       " + node.CHL + "       " + node.CHR + "       " + Math.Round(node.M, 5) + "      " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree                        
                    else
                    {
                        wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       0       0       " + Math.Round(node.M, 5) + "      " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree
                        node.CHR = 0;
                        node.CHL = 0;
                    }

                    nL += 2;// zwiekszamy nazwe pliku o 2
                    nR += 2;// zwiekszamy nazwe pliku o 2

                    wfL.Close();
                    wfR.Close();

                }//koniec if sprawdzajacy CHL i CHR czy sie dzieli
                else
                {
                    PNS.Enqueue(node.GNN);//jesli sie rodzic nie dzieli to musimy zapamietac
                    if (node.M == 0)
                    {
                        node.M = average(AJ[AJ.Length - 1]); node.V = variance(AJ[AJ.Length - 1], average(AJ[AJ.Length - 1]));
                        node.NV = AJ[0].Length;
                    }
                    if (node.NV < mNV || node.V < mVN) { node.SAN = 0; node.SAV = 0; node.NV = AJ[0].Length; }

                    node.CHR = 0;
                    node.CHL = 0;
                    //rVerification.AppendText(Convert.ToString(node.GNN + "                   " + node.L + "             " + node.N + "              " + node.P + "           " + node.CHL + "           " + node.CHR + "       " + Math.Round(node.M, 5) + "        " + Math.Round(node.V, 5) + "       " + node.NV + "       " + node.SAN + "         " + Math.Round(node.SAV, 5) + "\n"));

                    wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       0       0       " + Math.Round(node.M, 5) + "      " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree
                }

                dr[0] = node.GNN.ToString();
                dr[1] = node.L.ToString();
                dr[2] = node.N.ToString();
                dr[3] = node.P.ToString();
                dr[4] = node.CHL.ToString();
                dr[5] = node.CHR.ToString();
                dr[6] = Math.Round(node.M, 5).ToString();
                dr[7] = Math.Round(node.V, 5).ToString();
                dr[8] = node.NV.ToString();
                dr[9] = node.SAN.ToString();
                dr[10] = Math.Round(node.SAV, 5).ToString();

                TreeDT.Rows.Add(dr);

                if (N == nN2) { L++; nN2 = nN; nN = 0; N = 0; }//zwiekszanie poziomu gdy przejdziemy przez wszystkie wezly na danym poziomie
                N++;
                nP++;// do zmiany rodzica 

                if (L > mL) { break; } //po osiegnieciu poziomu konczymy 

            } //petla dla wezla w            
            wfT.Close(); // zamykanie plik    

            GNN = 0; L = 1; N = 1; P = 0;

            AssignAJTree(TreeDT);

            AJT = symulation();
            AssignSymulationDT();
            ChangeTreeDT();
            Quality = Math.Round(quality(AJT),5).ToString();

            AJT = null;
            AJTrain = null;
            AJTree = null;
            AJ = null;
            GC.Collect();
        }//TreeD  

        public void ChangeTreeDT()
        {
            TreeDT = new DataTable();
            TreeDT.Columns.Add(new DataColumn("GNNumber", typeof(int)));
            TreeDT.Columns.Add(new DataColumn("Level", typeof(int)));
            TreeDT.Columns.Add(new DataColumn("Node", typeof(int)));
            TreeDT.Columns.Add(new DataColumn("Parent", typeof(int)));
            TreeDT.Columns.Add(new DataColumn("ChildL", typeof(int)));
            TreeDT.Columns.Add(new DataColumn("ChildR", typeof(int)));
            TreeDT.Columns.Add(new DataColumn("Mean", typeof(double)));
            TreeDT.Columns.Add(new DataColumn("Variance", typeof(double)));
            TreeDT.Columns.Add(new DataColumn("NumVect", typeof(int)));
            TreeDT.Columns.Add(new DataColumn("SANumber", typeof(int)));
            TreeDT.Columns.Add(new DataColumn("SAValue", typeof(double)));
            TreeDT.Columns.Add(new DataColumn("Quality", typeof(double)));

            for (int i = 0; i < AJTree[0].Length; i++)
            {
                DataRow dr = TreeDT.NewRow();
                for (int j = 0; j <= AJTree.Length; j++)
                {
                    if (j < AJTree.Length)
                    {
                        dr[j] = AJTree[j][i];
                    }
                    else
                    {
                        dr[j] = Math.Round(AJT[1][i], 5);
                    }
                }
                TreeDT.Rows.Add(dr);
            }
        }

        public void AssignSymulationDT()
        {
            SymulationDT = new DataTable();
            SymulationDT.Columns.Add(new DataColumn("Number", typeof(string)));
            SymulationDT.Columns.Add(new DataColumn("Node", typeof(string)));
            SymulationDT.Columns.Add(new DataColumn("Quality", typeof(string)));
            SymulationDT.Columns.Add(new DataColumn("Attribute", typeof(string)));
            for (int j = 0; j < AJT[0].Length; j++)
            {
                DataRow dr = SymulationDT.NewRow();
                dr[0] = j;
                for (int i = 0; i < AJT.Length; i++)
                {
                    dr[i + 1] = Math.Round(AJT[i][j], 5).ToString();
                }
                SymulationDT.Rows.Add(dr);
            }
        }

        public void AssignAJTree(DataTable data)
        {
            AJTree = new double[data.Columns.Count][];

            for (int i = 0; i < data.Columns.Count; i++)
            {
                AJTree[i] = data.AsEnumerable().Select(row => Convert.ToDouble(row[i])).ToArray();
            }
        }

        public void AssignAJ(DataTable data)
        {
            AJ = new double[data.Columns.Count][];

            for (int i = 0; i < data.Columns.Count; i++)
            {
                AJ[i] = data.AsEnumerable().Select(row => row.Field<double>(i)).ToArray();
            }
            //ajtrain ma takie same dane
            AJTrain = AJ;
        }

        public void loadFile(System.Windows.Controls.TextBox tX, System.Windows.Controls.TextBox tY)
        {
            CultureInfo ci = new System.Globalization.CultureInfo("en-us");
            Thread.CurrentThread.CurrentCulture = ci;
            StreamReader sr2;
            int y = 0;
            int x = 0;
            string line;

            try
            {
                OpenFileDialog open = new OpenFileDialog();
                open.ShowDialog();
                if (open.FileName != "")
                {
                    StreamReader sr = new StreamReader(open.FileName);

                    while ((line = sr.ReadLine()) != null)
                    {
                        if (y == 0)
                        {
                            string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                            for (int i = 0; i < words.Length; i++)
                            {
                                x++;
                            }
                        }
                        if (line != "")
                        { y++; }
                    }
                    sr.Close();

                    AJ = new double[x][];//tworzymy tablice z x kolumn.
                    for (int i = 0; i < x; i++)
                    {
                        AJ[i] = new double[y]; //tworzymy tablice z y wierszami  
                    }

                    sr2 = new StreamReader(open.FileName);//wczytywanie danych to tablicy AJ
                    y = 0;

                    while ((line = sr2.ReadLine()) != null)
                    {
                        string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                        x = 0;
                        for (int i = 0; i < words.Length; i++)
                        {
                            words[i] = words[i].Replace(",", ".");
                            AJ[x][y] = double.Parse(words[i]);
                            x++;
                        }

                        if (line != "")
                        { y++; }
                    }
                    tX.Text = (x - 1).ToString();
                    tY.Text = y.ToString();
                    sr2.Close();

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading file data to create tree \n" + ex.ToString());
            }
        }

        public void loadFileFromPath(string path)
        {
            CultureInfo ci = new System.Globalization.CultureInfo("en-us");
            Thread.CurrentThread.CurrentCulture = ci;
            StreamReader sr2;
            int y = 0;
            int x = 0;
            string line;

            try
            {
                if (path != "")
                {
                    StreamReader sr = new StreamReader(path);

                    while ((line = sr.ReadLine()) != null)
                    {
                        if (y == 0)
                        {
                            string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                            for (int i = 0; i < words.Length; i++)
                            {
                                x++;
                            }
                        }
                        if (line != "")
                        { y++; }
                    }
                    sr.Close();

                    AJ = new double[x][];//tworzymy tablice z x kolumn.
                    for (int i = 0; i < x; i++)
                    {
                        AJ[i] = new double[y-1]; //tworzymy tablice z y wierszami
                    }

                    sr2 = new StreamReader(path);//wczytywanie danych do tablicy AJ
                    y = 0;

                    while ((line = sr2.ReadLine()) != null)
                    {
                        string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                        x = 0;

                        if (y != 0)
                        {
                            for (int i = 0; i < words.Length; i++)
                            {
                                words[i] = words[i].Replace(",", ".");
                                AJ[x][y-1] = double.Parse(words[i]);

                                x++;
                            }
                        }

                        if (line != "")
                        { y++; }
                    }
                    sr2.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading file data to create tree \n" + ex.ToString());
            }
        }

        public void loadFileTreePath(string path)
        {
            CultureInfo ci = new System.Globalization.CultureInfo("en-us");
            Thread.CurrentThread.CurrentCulture = ci;
            StreamReader sr2;
            int y = 0;
            int x = 0;
            string line;

            try
            {
                if (path != "")
                {
                    StreamReader sr = new StreamReader(path);

                    while ((line = sr.ReadLine()) != null)
                    {
                        if (y == 1)
                        {
                            string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                            for (int i = 0; i < words.Length; i++)
                            {
                                x++;
                            }
                        }
                        if (line != "")
                        { y++; }
                    }
                    sr.Close();
                    y -= 1;//zmniejszamy o jeden, bo pierwszy wiersz to nazwy

                    AJTree = new double[x][];//tworzymy tablice z x kolumn.
                    for (int i = 0; i < x; i++)
                    {
                        AJTree[i] = new double[y]; //tworzymy tablice z y wierszami
                    }

                    sr2 = new StreamReader(path);//wczytywanie danych to tablicy AJ
                    y = 0;
                    int tmp = 0;
                    while ((line = sr2.ReadLine()) != null)
                    {
                        string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                        x = 0;
                        if (tmp > 0)
                        {
                            for (int i = 0; i < words.Length; i++)
                            {
                                words[i] = words[i].Replace(",", ".");
                                AJTree[x][y] = double.Parse(words[i]);
                                x++;
                            }
                            if (line != "")
                            { y++; }
                        }
                        tmp++;
                    }
                    sr2.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading file data to create tree \n" + ex.ToString());
            }
        }

        public void loadFileTree()
        {
            CultureInfo ci = new System.Globalization.CultureInfo("en-us");
            Thread.CurrentThread.CurrentCulture = ci;
            StreamReader sr2;
            int y = 0;
            int x = 0;
            string line;

            try
            {
                OpenFileDialog open = new OpenFileDialog();
                open.ShowDialog();
                if (open.FileName != "")
                {
                    StreamReader sr = new StreamReader(open.FileName);

                    while ((line = sr.ReadLine()) != null)
                    {
                        if (y == 1)
                        {
                            string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                            for (int i = 0; i < words.Length; i++)
                            {
                                x++;
                            }
                        }
                        if (line != "")
                        { y++; }
                    }
                    sr.Close();
                    y -= 1;//zmniejszamy o jeden, bo pierwszy wiersz to nazwy

                    AJTree = new double[x][];//tworzymy tablice z x kolumn.
                    for (int i = 0; i < x; i++)
                    {
                        AJTree[i] = new double[y]; //tworzymy tablice z y wierszami
                    }

                    sr2 = new StreamReader(open.FileName);//wczytywanie danych to tablicy AJ
                    y = 0;
                    int tmp = 0;
                    while ((line = sr2.ReadLine()) != null)
                    {
                        string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                        x = 0;
                        if (tmp > 0)
                        {
                            for (int i = 0; i < words.Length; i++)
                            {
                                words[i] = words[i].Replace(",", ".");
                                AJTree[x][y] = double.Parse(words[i]);
                                x++;
                            }
                            if (line != "")
                            { y++; }
                        }
                        tmp++;
                    }
                    sr2.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading file data to create tree \n" + ex.ToString());
            }
        }

        public void loadFileSPath(string path)
        {
            CultureInfo ci = new System.Globalization.CultureInfo("en-us");
            Thread.CurrentThread.CurrentCulture = ci;
            StreamReader sr2;
            int y = 0;
            int x = 0;
            string line;

            try
            {

                if (path != "")
                {
                    StreamReader sr = new StreamReader(path);

                    while ((line = sr.ReadLine()) != null)
                    {
                        if (y == 0)
                        {
                            string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                            for (int i = 0; i < words.Length; i++)
                            {
                                x++;
                            }
                        }
                        if (line != "")
                        { y++; }
                    }
                    sr.Close();

                    AJTrain = new double[x][];//tworzymy tablice z x kolumn.
                    for (int i = 0; i < x; i++)
                    {
                        AJTrain[i] = new double[y - 1]; //tworzymy tablice z y wierszami
                    }

                    sr2 = new StreamReader(path);//wczytywanie danych to tablicy AJ
                    y = 0;

                    while ((line = sr2.ReadLine()) != null)
                    {
                        string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                        x = 0;

                        if (y > 0)
                        {
                            for (int i = 0; i < words.Length; i++)
                            {
                                words[i] = words[i].Replace(",", ".");
                                AJTrain[x][y - 1] = double.Parse(words[i]);

                                x++;
                            }
                        }
                        if (line != "")
                        { y++; }
                    }
                    sr2.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading file data to create tree \n" + ex.ToString());
            }
        }

        public void loadFileS()
        {
            CultureInfo ci = new System.Globalization.CultureInfo("en-us");
            Thread.CurrentThread.CurrentCulture = ci;
            StreamReader sr2;
            int y = 0;
            int x = 0;
            string line;

            try
            {
                OpenFileDialog open = new OpenFileDialog();
                open.ShowDialog();
                if (open.FileName != "")
                {
                    StreamReader sr = new StreamReader(open.FileName);

                    while ((line = sr.ReadLine()) != null)
                    {
                        if (y == 0)
                        {
                            string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                            for (int i = 0; i < words.Length; i++)
                            {
                                x++;
                            }
                        }
                        if (line != "")
                        { y++; }
                    }
                    sr.Close();

                    AJTrain = new double[x][];//tworzymy tablice z x kolumn.
                    for (int i = 0; i < x; i++)
                    {
                        AJTrain[i] = new double[y]; //tworzymy tablice z y wierszami
                    }

                    sr2 = new StreamReader(open.FileName);//wczytywanie danych to tablicy AJ
                    y = 0;

                    while ((line = sr2.ReadLine()) != null)
                    {
                        string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                        x = 0;

                        for (int i = 0; i < words.Length; i++)
                        {
                            words[i] = words[i].Replace(",", ".");
                            AJTrain[x][y] = double.Parse(words[i]);
                            x++;

                        }
                        if (line != "")
                        { y++; }
                    }
                    sr2.Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error loading file data to create tree \n" + ex.ToString());
            }
        }


        public void saveCriteria(String mnv, String mnvp, String ml, String mvn)
        {
            String fileNameC = "criteria.txt";
            FileStream fsC = new FileStream(fileNameC, FileMode.Create, FileAccess.Write);
            StreamWriter wfC = new StreamWriter(fsC);
            wfC.WriteLine(mnv);
            wfC.WriteLine(mnvp);
            wfC.WriteLine(ml);
            wfC.WriteLine(mvn);
            wfC.Close();
        }

        public static double average(double[] X)
        {
            double a = 0;
            for (int i = 0; i < X.Length; i++)
            {
                a = a + X[i];
            }
            a = a / X.Length;
            return a;
        } //sprawdzone OK

        public static double variance(double[] X, double av)
        {
            double v = 0;
            for (int i = 0; i < X.Length; i++)
            {
                v = v + Math.Pow((X[i] - av), 2);
            }
            v = v / X.Length;

            return v;
        }// sprawdzone OK

        public void saveFile(String namefile) //zapisywanie zbiorow
        {
            FileStream fs = new FileStream(namefile, FileMode.Append, FileAccess.Write);//Tworzenie plików do zapisywania zbiorow            
            StreamWriter wf = new StreamWriter(fs);

            for (int i = 0; i < AJ[0].Length; i++)
            {
                for (int j = 0; j < AJ.Length; j++)
                {
                    wf.Write(AJ[j][i] + "   ");
                } 
                wf.WriteLine();
            } 
            wf.Close();
        }

        public double[][] readFile(String namefile) //wczytywanie plikow (Nodes)
        {
            String line;
            int x = 0, y = 0;

            rf = new StreamReader(namefile);
            while ((line = rf.ReadLine()) != null)//sprawdzanie ile plik ma  X i Y
            {
                if (y == 0)
                {
                    string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 0; i < words.Length; i++)
                    {
                        x++;
                    }
                }
                if (line != "")
                { y++; }
            }
            rf.Close();

            AJ = new double[x][];//tworzymy tablice z x kolumn.
            for (int i = 0; i < x; i++)
            {
                AJ[i] = new double[y]; //tworzymy tablice z y wierszami
            }

            StreamReader rf2 = new StreamReader(namefile);//wczytywanie danych to tablicy AJ
            y = 0;

            while ((line = rf2.ReadLine()) != null)
            {
                string[] words = line.Trim().Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
                x = 0;

                for (int i = 0; i < words.Length; i++)
                {
                    AJ[x][y] = double.Parse(words[i]);
                    x++;
                }
                if (line != "")
                { y++; }
            }
            rf2.Close();

            return AJ;
        }

        public bool verificationNode(nodesLR nodeLR, double chMVN, int chMNV, int chMNVP) //sprawdzanie ChL CHR czy spełniaja warunki podziału
        {

            if (nodeLR.NV >= chMNVP)//sprawdzanie czy ilosc wektorow rodzica jest wieksza od minimalnej ilosci podanej
            {
                if (nodeLR.V >= chMVN)//sprawdzanie czy wariancja wezla jest wieksza od min wariancji
                {
                    if (nodeLR.NL >= chMNV && nodeLR.NR >= chMNV) //sprawdzanie czy ilosc wektorow  L i R jest wieksza od min
                    {
                        return true;
                    }
                }
            }
            return false;
        }


        public void Quicksort(int low, int high, double[] Y) //low index najmnieszy, hight index najwiekszy Y tablica JA[][] mozemy wstawic AJ[] do sortowania
        {
            int i1 = low, j1 = high;
            double pivot = Y[low + (high - low) / 2];

            while (i1 <= j1)
            {
                while (Y[i1] < pivot)
                    i1++;
                while (Y[j1] > pivot)
                    j1--;
                if (i1 <= j1)
                {
                    for (int f = 0; f < AJ.Length; f++)//zamiana wierszy
                    {
                        //if (f != k) //0 - kolumna przez ktora sortujemy nie zmienia miejsca
                        {
                            double tmpD = AJ[f][i1];
                            AJ[f][i1] = AJ[f][j1];
                            AJ[f][j1] = tmpD;
                        }
                    }
                    i1++; j1--;
                }
            }
            if (low < j1)
                Quicksort(low, j1, Y);
            if (i1 < high)
                Quicksort(i1, high, Y);
        }//sprawdzone i dziala na 100% dobrze

        public void Quicksort2(int C, int low, int high, double[][] Y) //C - numer kolumny do sortowania(liczymy od zera) low index najmnieszy, hight index najwiekszy Y tablica JA[][] mozemy wstawic AJ[] do sortowania
        {
            int i1 = low, j1 = high;
            double pivot = Y[C][low + (high - low) / 2];

            while (i1 <= j1)
            {
                while (Y[C][i1] < pivot)
                    i1++;
                while (Y[C][j1] > pivot)
                    j1--;
                if (i1 <= j1)
                {
                    for (int f = 0; f < Y.Length; f++)//zamiana wierszy
                    {
                        //if (f != k) //0 - kolumna przez ktora sortujemy nie zmienia miejsca
                        {
                            double tmpD = Y[f][i1];
                            Y[f][i1] = Y[f][j1];
                            Y[f][j1] = tmpD;
                        }
                    }
                    i1++; j1--;
                }
            }
            if (low < j1)
                Quicksort2(C, low, j1, Y);
            if (i1 < high)
                Quicksort2(C, i1, high, Y);
        }//sprawdzone i dziala na 100% dobrze

        public nodesLR minVar(double[][] node, int mNVCH)
        {
            int y = (node[0].Length - 1);// -1 bo ostatnia kolumna to Y
            int x = (node.Length - 1);//-1 do QuickSorta X
            double[] TY = node[x];//przypisanie do tablicy wartosci
            double[] TYL;
            double[] TYR;
            int nC;//zapamietuje numer kolumny do kopiowania
            double red1 = 0;
            double red2 = 0;
            double varL;
            double varR;
            int tmp = 0;

            nodesLR nodeLR = new nodesLR(); // tworzymy obiekt ktory bedzie zawieral dane wezla L albo R

            for (int i = 0; i < x; i++)//szukanie najlepszej wariancji po kolumnach 
            {
                Quicksort(0, y, node[i]); //ok

                for (int j = mNVCH; j <= (node[0].Length - mNVCH); j++)// szukanie wariancji po wierszach ok
                {
                    if (node[i][j - 1] != node[i][j])//sprawdzanie czy nastepny wiersz jest rozny od poprzedniego -1 bo liczymy od 0 ok
                    {
                        varL = 0; varR = 0;//zerowanie variance 

                        TYL = new double[j];//tablica posiadajaca rozmiar j
                        for (int a = 0; a < j; a++)
                        {
                            TYL[a] = TY[a];//przepisanie liczb od 0 do j ;

                        }
                        varL = variance(TYL, average(TYL));// varL 

                        nC = TYL.Length;//nC numer tablicy od ktorej ma byc kopiowane (j bo adres j-1 jest w L)
                        TYR = new double[node[0].Length - TYL.Length];//tablica posiadajaca rozmiar (node.lenght-(j))
                        for (int a = 0; a < TYR.Length; a++)
                        {
                            TYR[a] = TY[nC];//przepisywanie liczb od j do konca tablicy
                            nC++;
                        }
                        varR = variance(TYR, average(TYR));//varR

                        red1 = (varL * TYL.Length) + (varR * TYR.Length);//OK liczymy varL i mnozymy razy ilosc wektorow i to samo z warP ok

                        if (tmp == 0)
                        {
                            tmp++; red2 = red1; nodeLR.varL = varL; nodeLR.varR = varR;
                            nodeLR.M = average(node[node.Length - 1]); nodeLR.V = variance(AJ[AJ.Length - 1], average(AJ[node.Length - 1]));
                            nodeLR.NV = node[0].Length; nodeLR.SAN = i + 1; nodeLR.SAV = (node[i][j - 1] + node[i][j]) / 2;
                            nodeLR.ML = average(TYL); nodeLR.MR = average(TYR); nodeLR.NL = TYL.Length; nodeLR.NR = TYR.Length;
                        }

                        if (red1 < red2)
                        {
                            red2 = red1; nodeLR.varL = varL; nodeLR.varR = varR;
                            nodeLR.M = average(node[node.Length - 1]); nodeLR.V = variance(node[node.Length - 1], average(node[node.Length - 1]));
                            nodeLR.NV = node[0].Length; nodeLR.SAN = i + 1; nodeLR.SAV = (node[i][j - 1] + node[i][j]) / 2;
                            nodeLR.ML = average(TYL); nodeLR.MR = average(TYR); nodeLR.NL = TYL.Length; nodeLR.NR = TYR.Length;
                        }

                    }//koniec if sprawdzajacy czy AJ[i][j-1] != AJ[i][j]

                }//koniec forj szukanie po wierszach j-tych 

            }//fori  koniec szukania punktu podzialu

            return nodeLR;
        }

        public nodesLR neuronMLP(double[][] node, int mNVCH)
        {
            int y = (node[0].Length - 1);// -1 bo ostatnia kolumna to Y
            int x = (node.Length - 1);//-1 do QuickSorta X
            double[] TY = node[x];//przypisanie do tablicy wartosci
            double[] TYL;
            double[] TYR;
            int nC;//zapamietuje numer kolumny do kopiowania
            double red1 = 0;
            double red2 = 0;
            double varL;
            double varR;
            int tmp = 0;

            nodesLR nodeLR = new nodesLR(); // tworzymy obiekt ktory bedzie zawieral dane wezla L albo R

            for (int i = 0; i < x; i++)//szukanie najlepszej wariancji po kolumnach 
            {
                Quicksort(0, y, node[i]); //ok

                for (int j = mNVCH; j <= (node[0].Length - mNVCH); j++)// szukanie wariancji po wierszach ok
                {
                    if (node[i][j - 1] != node[i][j])//sprawdzanie czy nastepny wiersz jest rozny od poprzedniego -1 bo liczymy od 0 ok
                    {
                        varL = 0; varR = 0;//zerowanie variance 

                        TYL = new double[j];//tablica posiadajaca rozmiar j
                        for (int a = 0; a < j; a++)
                        {
                            TYL[a] = TY[a];//przepisanie liczb od 0 do j ;
                        }
                        varL = variance(TYL, average(TYL));// varL 

                        nC = TYL.Length;//nC numer tablicy od ktorej ma byc kopiowane (j bo adres j-1 jest w L)
                        TYR = new double[node[0].Length - TYL.Length];//tablica posiadajaca rozmiar (node.lenght-(j))
                        for (int a = 0; a < TYR.Length; a++)
                        {
                            TYR[a] = TY[nC];//przepisywanie liczb od j do konca tablicy
                            nC++;
                        }
                        varR = variance(TYR, average(TYR));//varR

                        red1 = (varL * TYL.Length) + (varR * TYR.Length);//OK liczymy varL i mnozymy razy ilosc wektorow i to samo z warP ok

                        if (tmp == 0)
                        {
                            tmp++; red2 = red1; nodeLR.varL = varL; nodeLR.varR = varR;
                            nodeLR.M = average(node[node.Length - 1]); nodeLR.V = variance(AJ[AJ.Length - 1], average(AJ[node.Length - 1]));
                            nodeLR.NV = node[0].Length; nodeLR.SAN = i + 1; nodeLR.SAV = (node[i][j - 1] + node[i][j]) / 2;
                            nodeLR.ML = average(TYL); nodeLR.MR = average(TYR); nodeLR.NL = TYL.Length; nodeLR.NR = TYR.Length;
                        }

                        if (red1 < red2)
                        {
                            red2 = red1; nodeLR.varL = varL; nodeLR.varR = varR;
                            nodeLR.M = average(node[node.Length - 1]); nodeLR.V = variance(node[node.Length - 1], average(node[node.Length - 1]));
                            nodeLR.NV = node[0].Length; nodeLR.SAN = i + 1; nodeLR.SAV = (node[i][j - 1] + node[i][j]) / 2;
                            nodeLR.ML = average(TYL); nodeLR.MR = average(TYR); nodeLR.NL = TYL.Length; nodeLR.NR = TYR.Length;
                        }
                    }//koniec if sprawdzajacy czy AJ[i][j-1] != AJ[i][j]

                }//koniec forj szukanie po wierszach j-tych 

            }//fori  koniec szukania punktu podzialu

            if (nodeLR.V < mVN || nodeLR.NV < mNVP || nodeLR.NL < mNV || nodeLR.NR < mNV)//  jesli wwezel ma mniejsza wariancje od min lub mnijsza ilosc wektorow od minimalnej 
            {
                double[,] AJ2 = new double[node[0].Length, node.Length];

                for (int i = 0; i < node[0].Length; i++)//kopiowanie tablicy
                {
                    for (int j = 0; j < node.Length; j++)
                    {
                        AJ2[i, j] = node[j][i];
                    }
                }

                MLP mlp = new MLP(AJ2, AJ2, 2, 2);//uruchomienie sieci
                double[] AJPSVY = new double[node[0].Length];
                double[] AJPSVX = new double[node.Length - 1];

                for (int y2 = 0; y2 < AJ[0].Length; y2++)
                {
                    for (int x2 = 0; x2 < AJ.Length - 1; x2++)
                    {
                        AJPSVX[x2] = AJ2[y2, x2];
                    }
                    AJPSVY[y2] = mlp.propagateSingleVector(AJPSVX);
                }
                nodeLR.M = average(AJPSVY);
                nodeLR.V = nodeLR.V = variance(node[node.Length - 1], average(node[node.Length - 1]));
            }
            return nodeLR;
        }

        public double[][] symulation()
        {
            int l = AJTrain[0].Length;
            double[][] AJQ = new double[3][];
            AJQ[0] = new double[l];
            AJQ[1] = new double[l];
            AJQ[2] = new double[l];

            int numA = 0;// numer atrybutu z wektora Train

            for (int iTrain = 0; iTrain < AJTrain[0].Length; iTrain++)
            {
                for (int iTree = 0; iTree < AJTree[0].Length; iTree++)
                {
                    if (AJTrain[numA][iTrain] > AJTree[6][iTree])//jesli wiekszy to na prawo
                    {

                        if (AJTree[5][iTree] == 0)
                        {
                            AJQ[0][iTrain] = AJTree[0][iTree];//zapamietywanie wezla ostatniego
                            AJQ[1][iTrain] = Math.Pow((Math.Abs(AJTree[6][iTree]) - Math.Abs(AJTrain[numA][iTrain])), 2);
                            AJQ[2][iTrain] = AJTrain[numA][iTrain];
                            break;
                        }
                        else
                        {
                            iTree = (int)AJTree[5][iTree];//przypisanie wezla, do ktorego ma wejsc
                            iTree -= 2;
                        }
                    }
                    else
                    {
                        if (AJTree[4][iTree] == 0)
                        {
                            AJQ[0][iTrain] = AJTree[0][iTree];//zapamietywanie wezla ostatniego
                            AJQ[1][iTrain] = Math.Pow((Math.Abs(AJTree[6][iTree]) - Math.Abs(AJTrain[numA][iTrain])), 2);
                            AJQ[2][iTrain] = AJTrain[numA][iTrain];
                            break;
                        }
                        else
                        {
                            iTree = (int)AJTree[4][iTree];//przypisanie wezla, do ktorego ma wejsc
                            iTree -= 2;
                        }
                    }
                }
            }
            return AJQ;
        }

        public static double quality(double[][] AJT)
        {
            double sumaQ = 0;
            for (int i = 0; i < AJT[0].Length; i++)
            {
                sumaQ += AJT[1][i];
            }

            sumaQ = Math.Sqrt(sumaQ / AJT[1].Length);
            return sumaQ;
        }

        public nodesLR minVar2A(double[][] node, int mNVCH)
        {
            double[][] AJR = new double[3][];//tablica zapamietujaca najlepsza redukcje w kazdej z kolumn
            AJR[0] = new double[node.Length - 1];// zapamietywanie kolumny
            AJR[1] = new double[node.Length - 1];// zapamietywanie atrybutu
            AJR[2] = new double[node.Length - 1];// zapamietywanie redukcji

            int y = (node[0].Length - 1);// -1 bo ostatnia kolumna to Y
            int x = (node.Length - 1);//-1 do QuickSorta X
            double[] TY = node[x];//przypisanie do tablicy wartosci
            double[] TYL;
            double[] TYR;
            int nC;//zapamietuje numer kolumny do kopiowania
            double red1 = 0;
            double red2 = 0;
            double varL;
            double varR;
            int tmp = 0;
            int nCHL = 0;// ilosc wektorow w L
            int nCHR = 0;// ilosc wektorow w R

            nodesLR nodeLR = new nodesLR(); // tworzymy obiekt ktory bedzie zawieral dane wezla L albo R

            for (int i = 0; i < x; i++)//szukanie najlepszej wariancji po kolumnach 
            {
                Quicksort(0, y, node[i]); //ok
                tmp = 0;// zmiana kolumny,szukanie nowej red var

                for (int j = mNVCH; j <= (node[0].Length - mNVCH); j++)// szukanie wariancji po wierszach 
                {
                    if (node[i][j - 1] != node[i][j])//sprawdzanie czy nastepny wiersz jest rozny od poprzedniego -1 bo liczymy od 0 ok
                    {
                        varL = 0; varR = 0;//zerowanie variance 

                        TYL = new double[j];//tablica posiadajaca rozmiar j
                        for (int a = 0; a < j; a++)
                        {
                            TYL[a] = TY[a];//przepisanie liczb od 0 do j ;
                        }
                        varL = variance(TYL, average(TYL));// varL 

                        nC = TYL.Length;//nC numer tablicy od ktorej ma byc kopiowane (j bo adres j-1 jest w L)
                        TYR = new double[node[0].Length - TYL.Length];//tablica posiadajaca rozmiar (node.lenght-(j))
                        for (int a = 0; a < TYR.Length; a++)
                        {
                            TYR[a] = TY[nC];//przepisywanie liczb od j do konca tablicy
                            nC++;
                        }
                        varR = variance(TYR, average(TYR));//varR

                        red1 = (varL * TYL.Length) + (varR * TYR.Length);//OK liczymy varL i mnozymy razy ilosc wektorow i to samo z warP ok

                        if (tmp == 0)
                        {
                            red2 = red1;
                            AJR[0][i] = i; // numer kolumny
                            AJR[1][i] = (node[i][j - 1] + node[i][j]) / 2; // atrybut  
                            AJR[2][i] = red2;
                            tmp++;
                        }

                        if (red1 < red2)
                        {
                            red2 = red1;
                            AJR[0][i] = i; // numer kolumny
                            AJR[1][i] = (node[i][j - 1] + node[i][j]) / 2; // atrybut  
                            AJR[2][i] = red2;
                        }
                    }//koniec if sprawdzajacy czy AJ[i][j-1] != AJ[i][j]                
                }//koniec forj szukanie po wierszach j-tych 
            }//fori  koniec szukania punktu podzialu

            Quicksort2(2, 0, (AJR[0].Length - 1), AJR);// sortowanie kolumny z red var(2 pierwsze wiersz to najmniejsza red var)

            tmp = 0;
            double n = 0;//liczba zmieniajaca kat nachylenia prostej        
            for (int i = 1; i <= 12; i++)// szukamy najlepszej wariancji pochylajac prosta o wartosci 0, 0.2, 0.4,..,1
            {
                nCHL = 0;
                nCHR = 0;
                if (i == 7) { n = 0; };

                for (int iy = 0; iy < node[0].Length; iy++)// sprawdzanie rozmiaru tablicy  L i R
                {
                    if (i < 7)
                    {
                        if (node[(int)(AJR[0][0])][iy] + node[(int)(AJR[0][1])][iy] * n < AJR[1][0] + AJR[1][1] * n)
                        {
                            nCHL++;
                        }
                        else
                        {
                            nCHR++;
                        }
                    }
                    else
                    {
                        if (node[(int)(AJR[0][0])][iy] * n + node[(int)(AJR[0][1])][iy] < AJR[1][0] * n + AJR[1][1])
                        {
                            nCHL++;
                        }
                        else
                        {
                            nCHR++;
                        }
                    }
                }

                double[] TYL2 = new double[nCHL];
                double[] TYR2 = new double[nCHR];
                nCHL = 0;//numer tablicy TYL
                nCHR = 0;//numer tablicy TYR            

                for (int iy = 0; iy < node[0].Length; iy++)// dzielenie zbioru na L i R
                {
                    if (i < 7)
                    {
                        if (node[(int)(AJR[0][0])][iy] + node[(int)(AJR[0][1])][iy] * n < AJR[1][0] + AJR[1][1] * n)
                        {
                            TYL2[nCHL] = node[node.Length - 1][iy];
                            nCHL++;
                        }
                        else
                        {
                            TYR2[nCHR] = node[node.Length - 1][iy];
                            nCHR++;
                        }
                    }
                    else
                    {
                        if (node[(int)(AJR[0][0])][iy] * n + node[(int)(AJR[0][1])][iy] < AJR[1][0] * n + AJR[1][1])
                        {
                            TYL2[nCHL] = node[node.Length - 1][iy];
                            nCHL++;
                        }
                        else
                        {
                            TYR2[nCHR] = node[node.Length - 1][iy];
                            nCHR++;
                        }
                    }
                }

                varL = variance(TYL2, average(TYL2));// varL
                varR = variance(TYR2, average(TYR2));// varR

                red1 = (varL * TYL2.Length) + (varR * TYR2.Length);// redukcja wariancji               

                if (tmp == 0)
                {
                    red2 = red1;
                    tmp++;
                    nodeLR.varL = varL; nodeLR.varR = varR;
                    nodeLR.M = average(node[node.Length - 1]);
                    nodeLR.V = variance(node[node.Length - 1], average(node[node.Length - 1]));
                    nodeLR.NV = node[0].Length;
                    nodeLR.SAN = 0;
                    if (i < 7)
                    {
                        nodeLR.SAV = AJR[1][0] + AJR[1][1] * n;
                    }
                    else
                    {
                        nodeLR.SAV = AJR[1][0] * n + AJR[1][1];
                    }
                    nodeLR.ML = average(TYL2); nodeLR.MR = average(TYR2);
                    nodeLR.NL = TYL2.Length; nodeLR.NR = TYR2.Length;
                    nodeLR.isV1A = false;
                    nodeLR.nC1 = (int)(AJR[0][0]);
                    nodeLR.nC2 = (int)(AJR[0][1]);
                    nodeLR.mA = i;// zapisuje, ktory atrybut jest mnozony
                    nodeLR.lS = n;// zapisuje o ile zmieniamy atrybut
                }

                if (red1 < red2)
                {
                    red2 = red1;
                    nodeLR.varL = varL; nodeLR.varR = varR;
                    nodeLR.M = average(node[node.Length - 1]);
                    nodeLR.V = variance(node[node.Length - 1], average(node[node.Length - 1]));
                    nodeLR.NV = node[0].Length;
                    nodeLR.SAN = 0;

                    if (i < 7)
                    {
                        nodeLR.SAV = AJR[1][0] + AJR[1][1] * n;
                    }
                    else
                    {
                        nodeLR.SAV = AJR[1][0] * n + AJR[1][1];
                    }
                    nodeLR.ML = average(TYL2); nodeLR.MR = average(TYR2);
                    nodeLR.NL = TYL2.Length; nodeLR.NR = TYR2.Length;
                    nodeLR.isV1A = false;
                    nodeLR.nC1 = (int)(AJR[0][0]);
                    nodeLR.nC2 = (int)(AJR[0][1]);
                    nodeLR.mA = i;
                    nodeLR.lS = n;
                }
                n += 0.2;
            }
            return nodeLR;
        }

        public void saveTreeAll(TreeViewSettings TVS)
        {
            DataTable tab = new DataTable();
            tab.Columns.Add(new DataColumn("GNNumber", typeof(string)));
            tab.Columns.Add(new DataColumn("Level", typeof(string)));
            tab.Columns.Add(new DataColumn("Node", typeof(string)));
            tab.Columns.Add(new DataColumn("Parent", typeof(string)));
            tab.Columns.Add(new DataColumn("ChildL", typeof(string)));
            tab.Columns.Add(new DataColumn("ChildR", typeof(string)));
            tab.Columns.Add(new DataColumn("Mean", typeof(string)));
            tab.Columns.Add(new DataColumn("Variance", typeof(string)));
            tab.Columns.Add(new DataColumn("NumVect", typeof(string)));
            tab.Columns.Add(new DataColumn("SANumber", typeof(string)));
            tab.Columns.Add(new DataColumn("SAValue", typeof(string)));
            tab.Columns.Add(new DataColumn("Quality", typeof(string)));

            for (int i = 0; i < AJTree[0].Length; i++)
            {
                DataRow dr = tab.NewRow();
                for (int j = 0; j <= AJTree.Length; j++)
                {
                    if (j < AJTree.Length)
                    {
                        dr[j] = AJTree[j][i].ToString();
                    }
                    else
                    {
                        dr[j] = Math.Round(AJT[1][i],5).ToString();
                    }
                }
                tab.Rows.Add(dr);
            }

            TVS.DataViewGridTree = tab.DefaultView;

            string name;

            if (FileNameTreeQ == null)
                name = "TreeQ-" + DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".txt";
            else
                name = FileNameTreeQ;

            StreamWriter sw = new StreamWriter(name);

            for (int i = 0; i < tab.Columns.Count; i++)
            {
                sw.Write(tab.Columns[i].ColumnName + "\t");
            }
            sw.WriteLine();
            for (int i = 0; i < tab.Rows.Count; i++)
            {
                for (int j = 0; j < tab.Columns.Count; j++)
                {
                    sw.Write(tab.Rows[i][j] + "\t");
                }
                sw.WriteLine();
            }
            sw.Close();
        }

        public void saveTreeAllTarget(double[][] AJTree, double[][] AJQ, string path, string separator, double[] RMean)
        {
            DataTable tab = new DataTable();
            tab.Columns.Add(new DataColumn("GNNumber", typeof(string)));
            tab.Columns.Add(new DataColumn("Level", typeof(string)));
            tab.Columns.Add(new DataColumn("Node", typeof(string)));
            tab.Columns.Add(new DataColumn("Parent", typeof(string)));
            tab.Columns.Add(new DataColumn("ChildL", typeof(string)));
            tab.Columns.Add(new DataColumn("ChildR", typeof(string)));
            tab.Columns.Add(new DataColumn("Mean", typeof(string)));
            tab.Columns.Add(new DataColumn("Variance", typeof(string)));
            tab.Columns.Add(new DataColumn("NumVect", typeof(string)));
            tab.Columns.Add(new DataColumn("SANumber", typeof(string)));
            tab.Columns.Add(new DataColumn("SAValue", typeof(string)));
            tab.Columns.Add(new DataColumn("Quality", typeof(string)));
            tab.Columns.Add(new DataColumn("RegMean", typeof(string)));

            string sep = separator;
            if (sep == "\\t")
                sep = "\t";

            for (int i = 0; i < AJTree[0].Length; i++)
            {
                DataRow dr = tab.NewRow();
                for (int j = 0; j <= AJTree.Length; j++)
                {
                    if (j < AJTree.Length)
                    {
                        dr[j] = AJTree[j][i].ToString();
                    }
                    else
                    {
                        dr[j] = Math.Round(AJQ[1][i],5).ToString();
                    }
                }
                dr["RegMean"] = Math.Round(RMean[i],5).ToString();

                tab.Rows.Add(dr);
            }

            System.IO.StreamWriter sw = new System.IO.StreamWriter(path);

            for (int i = 0; i < tab.Columns.Count; i++)
            {
                if (i == 0)
                    sw.Write(tab.Columns[i].ColumnName);
                else
                    sw.Write(sep + tab.Columns[i].ColumnName);
            }
            sw.WriteLine();
            for (int i = 0; i < tab.Rows.Count; i++)
            {
                for (int j = 0; j < tab.Columns.Count; j++)
                {
                    if (j == 0)
                        sw.Write(tab.Rows[i][j]);
                    else
                        sw.Write(sep + tab.Rows[i][j]);
                }
                sw.WriteLine();
            }
            sw.Close();
        }

        void saveNodeVectSource()
        {
            StreamWriter sw = new StreamWriter(rootDirNameC + "\\NodeVectSource.txt");

            for (int i = 0; i < NodeVectSource.Columns.Count; i++)
            {
                if (i == 0)
                    sw.Write(NodeVectSource.Columns[i].ColumnName);
                else
                    sw.Write("\t" + NodeVectSource.Columns[i].ColumnName);
            }
            sw.WriteLine();
            for (int i = 0; i < NodeVectSource.Rows.Count; i++)
            {
                for (int j = 0; j < NodeVectSource.Columns.Count; j++)
                {
                    if (j == 0)
                        sw.Write(NodeVectSource.Rows[i][j]);
                    else
                        sw.Write("\t" + NodeVectSource.Rows[i][j]);
                }
                sw.WriteLine();
            }
            sw.Close();
        }
    }
}
